using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace UniversityContactCrawler
{
    class WebCrawler
    {
        // 线程安全集合存储结果
        private static readonly ConcurrentDictionary<string, HashSet<string>> FoundContacts = new();
        private static readonly ConcurrentBag<string> VisitedPages = new();
        
        // 改进后的正则表达式（匹配中国电话号码）
        private static readonly Regex PhoneRegex = new(@"(?<!\d)((0\d{2,3}[- ]?[1-9]\d{6,7})|(1[3-9]\d{9}))(?!\d)");
        
        // 高校域名特征
        private static readonly string[] EduDomains = { ".edu.cn", "大学", "学院" };
        
        // HTTP请求设置
        private static readonly WebClient Client = new WebClient();
        static WebCrawler()
        {
            Client.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
            Client.Encoding = System.Text.Encoding.UTF8;
        }

        static void Main()
        {
            Console.Write("请输入高校名称或地区(如'北京 大学')：");
            var keyword = Console.ReadLine()?.Trim();
            
            if (!string.IsNullOrEmpty(keyword))
            {
                ExecuteSearch(keyword + " 联系方式");
                DisplayResults();
            }
            else
            {
                Console.WriteLine("输入不能为空");
            }
        }

        static void ExecuteSearch(string query)
        {
            try
            {
                // 使用Bing搜索获取初始结果
                var searchUrl = $"https://www.bing.com/search?q={Uri.EscapeDataString(query)}&count=20";
                var searchContent = GetWebContent(searchUrl);
                
                if (searchContent != null)
                {
                    // 优先处理.edu.cn域名
                    var links = ExtractPageLinks(searchContent)
                        .OrderByDescending(IsEduSite)
                        .Take(10); // 限制初始爬取数量
                    
                    Parallel.ForEach(links, ProcessWebPage);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"搜索出错: {ex.Message}");
            }
        }

        static void ProcessWebPage(string pageUrl)
        {
            try
            {
                // 限制最大结果数
                if (FoundContacts.Count >= 100 || VisitedPages.Contains(pageUrl))
                    return;
                    
                VisitedPages.Add(pageUrl);
                Console.WriteLine($"正在爬取: {pageUrl}");
                
                var pageContent = GetWebContent(pageUrl);
                if (pageContent == null) return;
                
                // 提取电话号码
                ExtractPhoneNumbers(pageContent, pageUrl);
                
                // 如果是高校网站，继续深入爬取
                if (IsEduSite(pageUrl))
                {
                    var internalLinks = ExtractPageLinks(pageContent)
                        .Where(link => IsInternalLink(pageUrl, link))
                        .Take(5); // 限制每页爬取数量
                        
                    Parallel.ForEach(internalLinks, ProcessWebPage);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"处理页面出错: {pageUrl}, 错误: {ex.Message}");
            }
        }

        static void ExtractPhoneNumbers(string content, string sourceUrl)
        {
            foreach (Match match in PhoneRegex.Matches(content))
            {
                var phone = FormatPhoneNumber(match.Value);
                FoundContacts.AddOrUpdate(phone, 
                    new HashSet<string> { sourceUrl }, 
                    (_, set) => { set.Add(sourceUrl); return set; });
                
                if (FoundContacts.Count >= 100) break;
            }
        }

        static string FormatPhoneNumber(string phone)
        {
            // 统一格式：去除空格和横线
            return phone.Replace(" ", "").Replace("-", "");
        }

        static bool IsEduSite(string url)
        {
            return EduDomains.Any(domain => url.Contains(domain));
        }

        static bool IsInternalLink(string baseUrl, string link)
        {
            try
            {
                var baseUri = new Uri(baseUrl);
                var linkUri = new Uri(baseUri, link);
                return linkUri.Host == baseUri.Host;
            }
            catch
            {
                return false;
            }
        }

        static string GetWebContent(string url)
        {
            try
            {
                // 添加延迟防止被封
                System.Threading.Thread.Sleep(1000); 
                return Client.DownloadString(url);
            }
            catch (WebException ex)
            {
                Console.WriteLine($"访问失败: {url}, 状态: {ex.Status}");
                return null;
            }
        }

        static IEnumerable<string> ExtractPageLinks(string content)
        {
            return Regex.Matches(content, @"<a\s+[^>]*href=[""']([^""']+)[""']")
                       .Cast<Match>()
                       .Select(m => m.Groups[1].Value)
                       .Where(link => !string.IsNullOrEmpty(link))
                       .Select(link => link.StartsWith("http") ? link : "http:" + link)
                       .Distinct();
        }

        static void DisplayResults()
        {
            Console.WriteLine("\n=== 爬取结果 ===");
            Console.WriteLine($"已访问页面: {VisitedPages.Count}");
            Console.WriteLine($"找到联系方式: {FoundContacts.Count}\n");
            
            foreach (var contact in FoundContacts.OrderBy(c => c.Key))
            {
                Console.WriteLine($"{contact.Key} (来自 {contact.Value.Count} 个页面):");
                foreach (var url in contact.Value.Take(3))
                {
                    Console.WriteLine($"  - {url}");
                }
            }
            
            Console.WriteLine("\n按任意键退出...");
            Console.ReadKey();
        }
    }
}
